package com.hillky.springboot.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hillky.springboot.controller.request.BaseRequest;
import com.hillky.springboot.entity.Book;
import com.hillky.springboot.entity.Borrow;
import com.hillky.springboot.entity.Retur;
import com.hillky.springboot.entity.User;
import com.hillky.springboot.exception.ServiceException;
import com.hillky.springboot.mapper.BookMapper;
import com.hillky.springboot.mapper.BorrowMapper;
import com.hillky.springboot.mapper.UserMapper;
import com.hillky.springboot.mapper.po.BorrowReturCountPO;
import com.hillky.springboot.service.BorrowService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.*;

@Service
public class BorrowServiceImpl implements BorrowService {

    @Autowired
    private BorrowMapper borrowMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private BookMapper bookMapper;

    @Override
    public List<Borrow> list(){
        return borrowMapper.list();
    }

    @Override
    public PageInfo<Borrow> page(BaseRequest baseRequest) {
        PageHelper.startPage(baseRequest.getPageNum(), baseRequest.getPageSize());
        List<Borrow> borrows = borrowMapper.listByCondition(baseRequest);
        return new PageInfo<>(borrows);
    }

    @Override
    @Transactional
    public void save(Borrow borrow) {
        String userNO = borrow.getUserNo();
        String bookNo = borrow.getBookNo();
        User user=userMapper.getByUsername(userNO);
        if(ObjectUtil.isNull(user)){
            throw new ServiceException("用户信息有误");
        }
        Book book=bookMapper.getByBookNo(bookNo);
        if(ObjectUtil.isNull(book)){
            throw new ServiceException("书本信息有误");
        }

        //查询图书数量是否足够
        if(book.getNums()<=0){
            throw new ServiceException("该书数量不足，无法借阅该书");
        }
        //查询用户积分是否足够
        Integer account = user.getAccount();
        Integer score = book.getScore();
        score=score*borrow.getDays();
       if(account<score){
           throw new ServiceException("用户积分不够，无法借阅该书");
       }
        //更新用户积分
        user.setAccount(user.getAccount()-score);
        userMapper.update(user);
        //更新图书数量
        book.setNums(book.getNums()-1);
        bookMapper.update(book);
        //添加借阅记录
        borrow.setStatus("已借出");
        LocalDate now = LocalDate.now();
        LocalDate returnDate = now.plus(borrow.getDays(), ChronoUnit.DAYS);
        borrow.setReturnDate(returnDate);
        borrow.setScore(score);
        borrowMapper.save(borrow);
    }

    @Override
    public PageInfo<Retur> pageRetur(BaseRequest baseRequest) {
        PageHelper.startPage(baseRequest.getPageNum(), baseRequest.getPageSize());
        List<Retur> returs = borrowMapper.returListByCondition(baseRequest);
        return new PageInfo<>(returs);
    }

    @Override
    @Transactional
    public void saveRetur(Retur retur) {
        String bookNo = retur.getBookNo();
        Integer id = retur.getId();
        //更改book的数量
        bookMapper.updateNumsByBookNo(bookNo);

        //更新借书记录
        retur.setStatus("已归还");
        borrowMapper.updateStatus("已归还",id);
        //新增还书记录
        LocalDate now = LocalDate.now();
        retur.setRealDate(now);
        borrowMapper.saveRetur(retur);
        //计算积分
        Book book = bookMapper.getByBookNo(bookNo);
        Integer bookScore = book.getScore();
        LocalDate returnDate = retur.getReturnDate();
        int score=0;
        if(now.isBefore(returnDate)){
            long days = now.until(returnDate, ChronoUnit.DAYS);
            score= (int) (days*bookScore);
        }else if(now.isAfter(returnDate)){
            long days = now.until(returnDate, ChronoUnit.DAYS);
            score=(int) (days*bookScore);
        }
        //进行用户积分返还和锁定
        User user = userMapper.getByUsername(retur.getUserNo());
        Integer oldAccount = user.getAccount();
        Integer newAccount=Integer.valueOf(score)+oldAccount;
        if(newAccount<0){
            user.setStatus(false);
        }
        user.setAccount(newAccount);
        userMapper.update(user);

    }

    @Override
    public Borrow getById(Integer id) {
        Borrow borrow=borrowMapper.getById(id);
        return borrow;
    }

    @Override
    public void update(Borrow borrow) {
        borrow.setUpdateTime(new Date());
        borrowMapper.update(borrow);
        return;
    }

    @Override
    public void deleteById(Integer id) {
        borrowMapper.deleteById(id);
        return;
    }

    @Override
    public void deleteReturById(Integer id) {
        borrowMapper.deleteReturById(id);
    }

    @Override
    public Map<String, Object> getCountByTimeRange(String timeRange) {
        HashMap<String, Object> map = new HashMap<>();
        //第一个值为就是日期字符串
        Date today=new Date();
        List<DateTime> dateRange;
        switch (timeRange){
            case "week":
                dateRange=DateUtil.rangeToList(DateUtil.offsetDay(today,-6),today,DateField.DAY_OF_WEEK);
                break;
            case "month":
                dateRange=DateUtil.rangeToList(DateUtil.offsetDay(today,-29),today,DateField.DAY_OF_MONTH);
                break;
            case "month2":
                dateRange=DateUtil.rangeToList(DateUtil.offsetDay(today,-59),today,DateField.DAY_OF_MONTH);
                break;
            case "month3":
                dateRange=DateUtil.rangeToList(DateUtil.offsetDay(today,-89),today,DateField.DAY_OF_MONTH);
                break;
            default:
                dateRange=new ArrayList<>();
        }
        List<String> dateStrRange=datetimeToDateStr(dateRange);
        map.put("date",dateStrRange);

        // getCountByTimeRange 不会统计数据库没有的日期，比如 数据库 11.4 这一天数据没有，他不会返回 date=2022-11-04,count=0 这个数据
        List<BorrowReturCountPO> borrowCount=borrowMapper.getCountByTimeRange(timeRange,1);
        List<BorrowReturCountPO> returCount=borrowMapper.getCountByTimeRange(timeRange,2);
        map.put("borrow", countList(borrowCount, dateStrRange));
        map.put("retur", countList(returCount, dateStrRange));
        return map;

    }

    //处理数据
    private List<Integer> countList(List<BorrowReturCountPO> countPOList, List<String> dateStrRange) {
        List<Integer> list = CollUtil.newArrayList();
        if (CollUtil.isEmpty(countPOList)) {
            return list;
        }
        for (String date : dateStrRange) {
           Integer count= countPOList.stream().filter(countPo->date.equals(countPo.getDate())).map(BorrowReturCountPO::getCount).findFirst().orElse(0);
           list.add(count);
        }
        // 最后返回的list的元素个数会跟 dateRange 的元素个数完全一样
        // dateRange: [
        //            "2022-10-30",
        //            "2022-10-31",
        //            "2022-11-01",
        //            "2022-11-02",
        //            "2022-11-03",
        //            "2022-11-04",
        //            "2022-11-05"
        //        ],
        // borrow: [
        //            0,
        //            0,
        //            2,
        //            1,
        //            0,
        //            1,
        //            3
        //        ]
        return list;
    }


    private List<String> datetimeToDateStr(List<DateTime> dateTimeList) {
        List<String> list = CollUtil.newArrayList();
        if (CollUtil.isEmpty(dateTimeList)) {
            return list;
        }
        for (DateTime dateTime : dateTimeList) {
            String formatDate = DateUtil.formatDate(dateTime);
            list.add(formatDate);
        }
        return list;
    }

}
